﻿#include <QIcon>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QVBoxLayout>

#include "plc_module.h"

PlcModule::PlcModule(QWidget* ui, ModbusManager* modbusManager, QObject* parent)
    : IModule(parent),
    ui_(ui),
    scene_(nullptr),
    modbusManager_(modbusManager),
    normallyOpen_(nullptr),
    normallyClosed_(nullptr),
    coil_(nullptr),
    greater_(nullptr),
    greaterEqual_(nullptr),
    less_(nullptr),
    lessEqual_(nullptr),
    equal_(nullptr),
    notEqual_(nullptr)
{
}

void PlcModule::setButtonStyle(QPushButton* button, const QString& text)
{
    QString buttonStyle = "QPushButton { background-color: transparent; border: none; }";
    button->setIconSize(QSize(30, 30));
    button->setStyleSheet(buttonStyle);
    button->setFixedSize(71, 31);
    button->setText(text);
}

void PlcModule::simpleSignals(PlcElement *elem)
{
    connect(elem, &PlcElement::writeCoilRequested, this, &PlcModule::onWriteCoilRequested);
    // 连接写寄存器信号
    connect(elem, &PlcElement::writeRegisterRequested, this, [this](int address, quint16 value) {
        Q_EMIT writeRegiseterRequested(address, value);
        qDebug() << u8"111111111:"<< address << value;
        Q_EMIT logMessageGenerated(QString(u8"PLC写寄存器请求：地址%1，值%2").arg(address).arg(value));
    });
    // 连接日志信号
    connect(elem, &PlcElement::logMessageRequested, this, [this](const QString& message) {
        // 转发到主窗口的日志系统
        Q_EMIT logMessageGenerated(message);
    });
    // 监听地址变更，维护监控集合
    connect(elem, &PlcElement::coilAddressChanged, this, [this](int oldAddr, int newAddr){
        Q_EMIT signalAddressChanged(oldAddr, newAddr);
        Q_EMIT logMessageGenerated(QString(u8"PLC线圈地址变更：%1 -> %2").arg(oldAddr).arg(newAddr));
    });

    // 监听寄存器地址变更，维护监控集合
    connect(elem, &PlcElement::registerAddress1Changed, this, [this, elem](int oldAddr, int newAddr){
        Q_EMIT logMessageGenerated(QString(u8"PLC寄存器地址1变更：%1 -> %2").arg(oldAddr).arg(newAddr));

        Q_EMIT signalRegisterChanged(oldAddr, newAddr);
        // 重置显示的寄存器值为0
        elem->setLeftRegisterValue(0);

        // 如果新地址在当前快照中有值，使用该值
        if (dRegisterSnapshot_.contains(newAddr))
        {
            elem->setLeftRegisterValue(dRegisterSnapshot_.value(newAddr));
        }
    });

    connect(elem, &PlcElement::registerAddress2Changed, this, [this, elem](int oldAddr, int newAddr){
        Q_EMIT logMessageGenerated(QString(u8"PLC寄存器地址2变更：%1 -> %2").arg(oldAddr).arg(newAddr));

         Q_EMIT signalRegisterChanged(oldAddr, newAddr);
        // 重置显示的寄存器值为0
        elem->setRightRegisterValue(0);

        // 如果新地址在当前快照中有值，使用该值
        if (dRegisterSnapshot_.contains(newAddr))
        {
            elem->setRightRegisterValue(dRegisterSnapshot_.value(newAddr));
        }
    });
}

void PlcModule::init()
{
    // 动态查找UI元素
    QWidget* plcToolWidget = ui_->findChild<QWidget*>("plcToolWidget");
    QWidget* tab = ui_->findChild<QWidget*>("tab");
    QGraphicsView* plcGraphicsView = ui_->findChild<QGraphicsView*>("plcGraphicsView");
    
    if (!plcToolWidget || !tab || !plcGraphicsView) {
        Q_EMIT logMessageGenerated(u8"PLC模块初始化失败：无法找到必要的UI元素");
        return;
    }

    normallyOpen_ = new QPushButton(plcToolWidget);
    normallyClosed_ = new QPushButton(plcToolWidget);
    coil_ = new QPushButton(plcToolWidget);
    greater_ = new QPushButton(plcToolWidget);
    greaterEqual_ = new QPushButton(plcToolWidget);
    less_ = new QPushButton(plcToolWidget);
    lessEqual_ = new QPushButton(plcToolWidget);
    equal_ = new QPushButton(plcToolWidget);
    notEqual_ = new QPushButton(plcToolWidget);
    // 设置工具栏的按钮样式
    setButtonStyle(normallyOpen_, "—| |—");
    setButtonStyle(normallyClosed_, "—|/|—");
    setButtonStyle(coil_, "—( )—");
    setButtonStyle(greater_, "—|>|—");
    setButtonStyle(greaterEqual_, "—|≥|—");
    setButtonStyle(less_, "—|<|—");
    setButtonStyle(lessEqual_, "—|≤|—");
    setButtonStyle(equal_, "—|=|—");
    setButtonStyle(notEqual_, "—|≠|—");
    // 创建工具栏垂直布局
    QVBoxLayout* toolLayout = new QVBoxLayout(plcToolWidget);
    toolLayout->setContentsMargins(5, 10, 5, 10);
    toolLayout->setSpacing(5);
    // 添加按钮到工具栏
    toolLayout->addWidget(normallyOpen_);
    toolLayout->addWidget(normallyClosed_);
    toolLayout->addWidget(coil_);
    toolLayout->addWidget(greater_);
    toolLayout->addWidget(greaterEqual_);
    toolLayout->addWidget(less_);
    toolLayout->addWidget(lessEqual_);
    toolLayout->addWidget(equal_);
    toolLayout->addWidget(notEqual_);
    // 将工具栏和视图添加到布局
    // 如果tab没有布局，创建一个布局
    if (tab->layout() == nullptr)
    {
        QHBoxLayout* layout = new QHBoxLayout(tab);
        layout->setContentsMargins(0, 0, 0, 0);
        tab->setLayout(layout);
    }
    tab->layout()->addWidget(plcToolWidget);
    tab->layout()->addWidget(plcGraphicsView);
    // 设置场景矩形，确保正确显示
    scene_ = new PlcGraphicsScene(plcGraphicsView, this);
    scene_->setSceneRect(0, 0, 686, 420);
    plcGraphicsView->setScene(scene_);

    // 设置视图属性确保网格可见，开抗锯齿确保折线的竖线粗细相同
    plcGraphicsView->setRenderHint(QPainter::Antialiasing, true);
    plcGraphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);

    //根据当前 sceneRect / 网格，创建每行 x=0 的锚点
    scene_->rebuildRowAnchors();

    connect(scene_, &PlcGraphicsScene::elementCreated, this, &PlcModule::onElementCreated);

    connect(normallyOpen_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::NORMALLYOPEN);
    });
    connect(normallyClosed_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::NORMALLYCLOSED);
    });
    connect(coil_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::COIL);
    });
    connect(greater_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::GREATER);
    });
    connect(greaterEqual_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::GREATEREQUAL);
    });
    connect(less_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::LESS);
    });
    connect(lessEqual_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::LESSEQUAL);
    });
    connect(equal_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::EQUAL);
    });
    connect(notEqual_, &QPushButton::clicked, this, [this]() {
        prepareToCreateElement(PlcInstructionType::NOTEQUAL);
    });
    connect(scene_, &PlcGraphicsScene::sceneContentChanged, this, [this](){
        isModified_ = true;
    });
    // 连接复制粘贴信号
    connect(scene_, &PlcGraphicsScene::copyRequestFromScene, this, &PlcModule::onCopyRequested);
    connect(scene_, &PlcGraphicsScene::pasteRequestFromScene, this, &PlcModule::onPasteRequested);

    // Modbus信号连接将在setModbusManager中处理

    dRegisterSnapshot_[0] = 0;  // D0 默认值
    dRegisterSnapshot_[1] = 0;  // D1 默认值
    applyDRegisterSnapshot(dRegisterSnapshot_);  // 应用默认的寄存器快照，进行初始检查

    //连接元件写线圈信号
    connect(scene_, &PlcGraphicsScene::elementCreated, this, [this](PlcElement* item){
        connect(item, &PlcElement::writeCoilRequested, this, &PlcModule::onWriteCoilRequested);
    });
}

// 写线圈请求处理
void PlcModule::onWriteCoilRequested(int address, bool value)
{
    // 通过信号请求写线圈操作，避免直接调用ModbusManager
    Q_EMIT IModule::writeCoilRequested(address, value);
    Q_EMIT logMessageGenerated(QString(u8"PLC写线圈请求：地址%1，值%2 -> 已发送写线圈请求").arg(address).arg(value ? u8"ON" : u8"OFF"));
}

void PlcModule::onCopyRequested()
{
    if (!scene_) return;

    // 获取选中的元件
    QList<QGraphicsItem*> selected = scene_->selectedItems();
    if (selected.isEmpty()) return;

    // 取第一个选中的元件
    PlcElement* itemToCopy = qgraphicsitem_cast<PlcElement*>(selected.first());
    if (!itemToCopy) return;

    // 保存元件属性到复制缓存
    copiedType_ = itemToCopy->instructionType();
    copiedSize_ = QSizeF(itemToCopy->boundingRect().width(), itemToCopy->boundingRect().height());
    copiedOn_ = itemToCopy->isOn();
    copiedPrefix_ = itemToCopy->propPrefix();
    copiedValue1_ = itemToCopy->propValue();
    copiedValue2_ = itemToCopy->propValue2();

    hasCopiedItem_ = true;
}

void PlcModule::onPasteRequested(const QPointF& scenePos)
{
    if (!hasCopiedItem_ || !scene_) return;

    // 粘贴前检查该网格是否已被占用
    if (scene_->isOccupied(scenePos)) return;

    // 创建新元件
    PlcElement* newItem = new PlcElement();
    newItem->setInstructionType(copiedType_);
    newItem->setSize(copiedSize_.width(), copiedSize_.height());
    newItem->setOn(copiedOn_);
    newItem->setPropPrefix(copiedPrefix_);
    newItem->setPropValue(copiedValue1_);
    newItem->setPropValue2(copiedValue2_);

    // 网格吸附
    const QPointF topLeft = scene_->snapTopLeftToCellCenter(scenePos, copiedSize_);
    newItem->setPos(topLeft);

    scene_->addItem(newItem);
    onElementCreated(newItem);

    isModified_ = true;
}

void PlcModule::prepareToCreateElement(PlcInstructionType type)
{
    scene_->setMode(PlcGraphicsScene::CREATE);
    scene_->setInstructionTypeToCreate(type);
}

void PlcModule::onElementCreated(PlcElement* item)
{
    simpleSignals(item);

    // 如果是线圈类元件，记录监控地址
    if (item->propPrefix().compare("M", Qt::CaseInsensitive) == 0)
    {
        int address = item->propValue();
        Q_EMIT signalAddressChanged(-1, address);
        Q_EMIT logMessageGenerated(QString(u8"PLC线圈元件注册地址：%1").arg(address));
    }

    // 如果是比较元件，记录寄存器地址
    if (item->isComparator() && item->propPrefix().compare("D", Qt::CaseInsensitive) == 0)
    {
        int d1Addr = item->propValue();
        int d2Addr = item->propValue2();
        Q_EMIT signalRegisterChanged(-1, d1Addr);
        Q_EMIT signalRegisterChanged(-1, d2Addr);
        qDebug()<<"ssssss";
        Q_EMIT logMessageGenerated(QString(u8"PLC比较元件注册寄存器：%1, %2").arg(d1Addr).arg(d2Addr));
    }

    // 如果是比较元件，立即使用当前寄存器快照更新状态
    if (item->isComparator()) {
        item->updateCompareStateFromD(dRegisterSnapshot_);
    }
    isModified_ = true; // 创建元件后标记
}

// 添加线圈更新处理（私有方法）
void PlcModule::updateCoilElements(int address, bool value) {
    // 更新所有匹配的线圈元件
    const auto itemsList = scene_->items();
    for (QGraphicsItem* it : itemsList)
    {
        if (it->type() == PlcElement::Type)
        {
            auto* elem = static_cast<PlcElement*>(it);

            // 只处理线圈类元件
            if (elem->propPrefix().compare("M", Qt::CaseInsensitive) == 0 && elem->propValue() == address)
            {
                elem->setOn(value);
            }
        }
    }
}

// 添加寄存器更新处理（私有方法）
void PlcModule::updateRegisterElements(int address, quint16 value)
{
    // 更新寄存器快照
    dRegisterSnapshot_[address] = value;

    // 更新所有显示这个寄存器地址的元件
    updateRegisterDisplay(address, value);

    // 更新所有比较元件
    applyDRegisterSnapshot(dRegisterSnapshot_);
}

void PlcModule::applyDRegisterSnapshot(const QHash<int, quint16>& dregs)
{
    if (!scene_)
    {
        return;
    }

    // 遍历场景，找到所有 PlcElement，若为比较元件则根据寄存器快照更新状态
    const auto itemsList = scene_->items();
    for (QGraphicsItem* it : itemsList)
    {
        if (it->type() == PlcElement::Type)
        {
            auto* elem = static_cast<PlcElement*>(it);
            if (elem->isComparator())
            {
                elem->updateCompareStateFromD(dregs);
            }
        }
    }
}

void PlcModule::updateRegisterDisplay(int address, quint16 value)
{
    if (!scene_) return;

    // 遍历所有元件，更新显示相同寄存器地址的元件
    const auto itemsList = scene_->items();
    for (QGraphicsItem* it : itemsList)
    {
        if (it->type() == PlcElement::Type)
        {
            auto* elem = static_cast<PlcElement*>(it);

            // 检查左寄存器是否匹配
            if (elem->propPrefix().compare("D", Qt::CaseInsensitive) == 0 && elem->propValue() == address)
            {
                // 更新左寄存器显示值
                elem->setLeftRegisterValue(value);
            }

            // 检查右寄存器是否匹配
            if (elem->propPrefix().compare("D", Qt::CaseInsensitive) == 0 && elem->propValue2() == address)
            {
                // 更新右寄存器显示值
                elem->setRightRegisterValue(value);
            }
        }
    }
}

void PlcModule::againRegisterAllCoils()
{
    if (!scene_) return;

    // 遍历所有元件，重新注册M前缀的线圈地址
    const auto itemsList = scene_->items();
    for (QGraphicsItem* it : itemsList)
    {
        if (it->type() == PlcElement::Type)
        {
            auto* elem = static_cast<PlcElement*>(it);
            if (elem->propPrefix().compare("M", Qt::CaseInsensitive) == 0)
            {
                int address = elem->propValue();
                Q_EMIT signalAddressChanged(-1, address);
                Q_EMIT logMessageGenerated(QString(u8"PLC重新注册线圈地址：%1").arg(address));
            }
        }
    }
}

// 重新注册所有寄存器的方法
void PlcModule::againRegisterAllRegisters()
{
    if (!scene_) return;

    // 遍历所有元件，重新注册D前缀的寄存器地址
    const auto itemsList = scene_->items();
    for (QGraphicsItem* it : itemsList)
    {
        if (it->type() == PlcElement::Type)
        {
            auto* elem = static_cast<PlcElement*>(it);
            if (elem->isComparator() && elem->propPrefix().compare("D", Qt::CaseInsensitive) == 0)
            {
                int d1Addr = elem->propValue();
                int d2Addr = elem->propValue2();
                Q_EMIT signalRegisterChanged(-1, d1Addr);
                Q_EMIT signalRegisterChanged(-1, d2Addr);
                Q_EMIT logMessageGenerated(QString(u8"PLC重新注册寄存器地址：%1, %2").arg(d1Addr).arg(d2Addr));
            }
        }
    }
}

void PlcModule::setSimulationRunning(bool running)
{
    // 设置所有元件的仿真状态
    PlcElement::setSimulationRunning(running);

    // 强制更新所有元件显示
    if (scene_)
    {
        const auto itemsList = scene_->items();
        for (QGraphicsItem* it : itemsList)
        {
            if (it->type() == PlcElement::Type)
            {
                it->update();
            }
        }
    }
}

// 重置（新建）
void PlcModule::resetDiagram()
{
    if (!scene_)
    {
        return;
    }

    // 安全清空：清图元 + 清空锚点指针数组
    scene_->clearAll();

    // 重新生成当前场景尺寸下的行锚点
    scene_->rebuildRowAnchors();

    isModified_ = false;

    // 重置寄存器快照为默认值
    dRegisterSnapshot_.clear();
    dRegisterSnapshot_[0] = 0;  // D0 默认值
    dRegisterSnapshot_[1] = 0;  // D1 默认值
    // 应用默认的寄存器快照
    applyDRegisterSnapshot(dRegisterSnapshot_);
}

bool PlcModule::isModified() const
{
    return isModified_;
}

void PlcModule::setModified(bool m)
{
    isModified_ = m;
}

// 保存
bool PlcModule::saveToFile(const QString& filePath)
{
    if (!scene_)
    {
        return false;
    }

    // 1、先收集所有元件，建立指针->索引映射
    QJsonArray elemArray;
    QList<PlcElement*> elems;
    QHash<const PlcElement*, int> indexOf;

    for (QGraphicsItem* it : scene_->items(Qt::AscendingOrder))
    {
        if (it->type() == PlcElement::Type)
        {
            auto* e = static_cast<PlcElement*>(it);
            const int idx = elems.size();
            elems.append(e);
            indexOf.insert(e, idx);

            QJsonObject obj;
            obj["type"]   = static_cast<int>(e->instructionType());
            obj["x"]      = e->pos().x();
            obj["y"]      = e->pos().y();
            obj["w"]      = e->boundingRect().width();
            obj["h"]      = e->boundingRect().height();
            obj["on"]     = e->isOn();
            obj["prefix"] = e->propPrefix();
            obj["v1"]     = e->propValue();
            obj["v2"]     = e->propValue2();

            elemArray.append(obj);
        }
    }

    // 2、再收集“元素-元素 / 元素-锚点”的连线
    QJsonArray connArray;
    for (QGraphicsItem* it : scene_->items(Qt::AscendingOrder))
    {
        if (it->type() != ConnectLine::Type)
        {
            continue;
        }
        auto* c = static_cast<ConnectLine*>(it);
        QJsonObject co;

        // 标出哪一端是锚点
        const bool sA = c->startIsAnchor();
        const bool eA = c->endIsAnchor();
        co["s_anchor"] = sA;
        co["e_anchor"] = eA;

        // 非锚点端存元素索引 + 端口侧（0=Left, 1=Right）
        if (!sA && c->startItem() && indexOf.contains(c->startItem()))
        {
            co["s_idx"]  = indexOf.value(c->startItem());
            co["s_side"] = (c->startSide() == ConnectLine::RIGHT ? 1 : 0);
        }
        else
        {
            co["s_idx"]  = -1;
            // 保存锚点坐标（场景坐标）
            const QPointF p = c->startAnchorScenePos();
            co["s_ax"] = p.x();
            co["s_ay"] = p.y();
        }

        if (!eA && c->endItem() && indexOf.contains(c->endItem()))
        {
            co["e_idx"]  = indexOf.value(c->endItem());
            co["e_side"] = (c->endSide() == ConnectLine::RIGHT ? 1 : 0);
        }
        else
        {
            co["e_idx"]  = -1;
            const QPointF p = c->endAnchorScenePos();
            co["e_ax"] = p.x();
            co["e_ay"] = p.y();
        }

        // 折线信息
        co["poly"] = c->isPolyline();
        if (c->isPolyline())
        {
            const QPointF b = c->bendPoint();
            co["bx"] = b.x();
            co["by"] = b.y();
        }

        connArray.append(co);
    }

    QJsonObject root;
    root["elements"]    = elemArray;
    root["connections"] = connArray;

    QJsonDocument doc(root);
    QFile f(filePath);
    if (!f.open(QIODevice::WriteOnly)) return false;
    f.write(doc.toJson(QJsonDocument::Indented));
    f.close();

    isModified_ = false;
    return true;
}

// 打开
bool PlcModule::openFromFile(const QString& filePath)
{
    QFile f(filePath);
    if (!f.open(QIODevice::ReadOnly))
    {
        return false;
    }

    const auto doc = QJsonDocument::fromJson(f.readAll());
    f.close();
    if (!doc.isObject())
    {
        return false;
    }

    resetDiagram();

    const auto root = doc.object();
    const auto elemArray = root.value("elements").toArray();
    const auto connArray = root.value("connections").toArray();

    // 先创建所有元件
    QVector<PlcElement*> created;
    created.reserve(elemArray.size());

    for (const auto& v : elemArray)
    {
        const auto obj = v.toObject();
        auto* e = new PlcElement();
        e->setInstructionType(static_cast<PlcInstructionType>(obj.value("type").toInt()));
        e->setSize(obj.value("w").toDouble(60.0), obj.value("h").toDouble(35.0));
        e->setOn(obj.value("on").toBool(false));
        e->setPropPrefix(obj.value("prefix").toString("M"));
        e->setPropValue(obj.value("v1").toInt(0));
        e->setPropValue2(obj.value("v2").toInt(0));
        e->setPos(QPointF(obj.value("x").toDouble(0.0), obj.value("y").toDouble(0.0)));

        scene_->addItem(e);
        created.push_back(e);
        // 信号连接
        simpleSignals(e);

        // 如果是线圈类元件，记录监控地址
        if (e->propPrefix().compare("M", Qt::CaseInsensitive) == 0)
        {
            int address = e->propValue();
            Q_EMIT signalAddressChanged(-1, address);
            Q_EMIT logMessageGenerated(QString(u8"PLC加载文件时注册线圈地址：%1").arg(address));
        }

        // 如果是比较元件，立即使用当前寄存器快照更新状态
        if (e->isComparator())
        {
            e->updateCompareStateFromD(dRegisterSnapshot_);
            // 确保显示值正确
            int d1Addr = e->propValue();
            int d2Addr = e->propValue2();

            if (dRegisterSnapshot_.contains(d1Addr)) {
                e->setLeftRegisterValue(dRegisterSnapshot_.value(d1Addr));
            } else {
                e->setLeftRegisterValue(0);
            }

            if (dRegisterSnapshot_.contains(d2Addr)) {
                e->setRightRegisterValue(dRegisterSnapshot_.value(d2Addr));
            } else {
                e->setRightRegisterValue(0);
            }
        }
    }

    // 创建连线
    for (const auto& v : connArray)
    {
        const auto obj = v.toObject();

        const bool sA = obj.value("s_anchor").toBool(false);
        const bool eA = obj.value("e_anchor").toBool(false);

        const int  si = obj.value("s_idx").toInt(-1);
        const int  ei = obj.value("e_idx").toInt(-1);
        const int  sside_i = obj.value("s_side").toInt(1); // 1=Right, 0=Left
        const int  eside_i = obj.value("e_side").toInt(0);

        const QPointF sAnchor(obj.value("s_ax").toDouble(0.0), obj.value("s_ay").toDouble(0.0));
        const QPointF eAnchor(obj.value("e_ax").toDouble(0.0), obj.value("e_ay").toDouble(0.0));

        ConnectLine* c = nullptr;

        // 1、两端都是元素
        if (!sA && !eA)
        {
            if (si < 0 || ei < 0 || si >= created.size() || ei >= created.size())
            {
                continue;
            }

            auto sside = sside_i ? ConnectLine::RIGHT : ConnectLine::LEFT;
            auto eside = eside_i ? ConnectLine::RIGHT : ConnectLine::LEFT;

            auto* start = created[si];
            auto* end   = created[ei];

            c = new ConnectLine(start, sside, end, eside);
            start->addConnection(c);
            end->addConnection(c);
        }
        // 2、art 是元素，end 是锚点（正常构造）
        else if (!sA && eA)
        {
            if (si < 0 || si >= created.size())
            {
                continue;
            }

            auto sside = sside_i ? ConnectLine::RIGHT : ConnectLine::LEFT;
            auto* start = created[si];

            c = new ConnectLine(start, sside, eAnchor);
            start->addConnection(c);
        }
        // 3、start 是锚点，end 是元素（以元素为 start，把锚点当 endAnchor）
        else if (sA && !eA)
        {
            if (ei < 0 || ei >= created.size())
            {
                continue;
            }

            auto eside = eside_i ? ConnectLine::RIGHT : ConnectLine::LEFT;
            auto* start = created[ei];
            c = new ConnectLine(start, eside, sAnchor);
            start->addConnection(c);
        }
        else
        {
            continue;
        }

        if (!c)
        {
            continue;
        }

        // 折线处理
        const bool poly = obj.value("poly").toBool(false);
        if (poly)
        {
            const QPointF bend(obj.value("bx").toDouble(0.0), obj.value("by").toDouble(0.0));
            c->setPolylineMode(true, bend);
        }

        scene_->addItem(c);
        c->updatePosition();
    }

    isModified_ = false;
    applyDRegisterSnapshot(dRegisterSnapshot_); // 打开文件后立即应用当前快照
    return true;
}

// IModule接口实现
void PlcModule::reset()
{
    resetDiagram();
}

QString PlcModule::getFileFilter() const
{
    return QString(u8"PLC文件 (*.plc)");
}

QString PlcModule::getModuleName() const
{
    return QString(u8"PLC");
}

// 仿真相关方法实现
void PlcModule::startSimulation(const QString& serialPort, int baudRate, int dataBits, int stopBits, int parity)
{
    if (!modbusManager_) return;
    
    // 设置仿真运行状态
    setSimulationRunning(true);
    
    // 重新注册所有线圈和寄存器
    againRegisterAllCoils();
    againRegisterAllRegisters();
    
    Q_EMIT logMessageGenerated(QString(u8"PLC仿真已启动：串口：%1，波特率：%2")
                             .arg(serialPort, QString::number(baudRate)));
}

void PlcModule::stopSimulation()
{
    if (!modbusManager_) return;
    
    // 设置仿真停止状态
    setSimulationRunning(false);
    
    Q_EMIT logMessageGenerated(u8"PLC仿真已停止");
}

bool PlcModule::isSimulationRunning() const
{
    return modbusManager_ != nullptr;
}

// 设置Modbus管理器
void PlcModule::setModbusManager(ModbusManager* modbusManager)
{
    modbusManager_ = modbusManager;
    
    // 信号连接将通过其他方式处理
    Q_EMIT logMessageGenerated(u8"PLC模块已设置ModbusManager");
}

// 实现IModule接口的Modbus数据更新方法
void PlcModule::onCoilUpdated(int address, bool value)
{
    // 调用现有的onCoilUpdated方法来更新PLC元件
    // 注意：这里需要重命名现有的私有方法以避免冲突
    updateCoilElements(address, value);
    Q_EMIT logMessageGenerated(QString(u8"PLC收到线圈更新：地址%1，值%2").arg(address).arg(value ? u8"ON" : u8"OFF"));
}

void PlcModule::onRegisterUpdated(int address, quint16 value)
{
    // 调用现有的onRegisterUpdated方法来更新PLC元件
    // 注意：这里需要重命名现有的私有方法以避免冲突
    updateRegisterElements(address, value);
    Q_EMIT logMessageGenerated(QString(u8"PLC收到寄存器更新：地址%1，值%2").arg(address).arg(value));
}
